package com.geor.gcv.core.model;

import org.nutz.json.Json;
import org.nutz.repo.Base64;
import org.opencv.core.Mat;
import org.opencv.core.Rect;

import com.geor.common.msg.XmlTool;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;

/**
 * 划分区域
 * 
 * @author geor.lusongnan
 *
 */
@XStreamAlias("area")
public class Area {
	@XStreamAlias("x")
	@XStreamAsAttribute
	protected int x;
	
	@XStreamAlias("y")
	@XStreamAsAttribute
	protected int y;
	
	@XStreamAlias("width")
	@XStreamAsAttribute
	protected int width;
	
	@XStreamAlias("height")
	@XStreamAsAttribute
	protected int height;

	public Area() {
		super();
	}

	public Area(int x, int y, int width, int height) {
		super();
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public Area check(Mat img) {
		int row = img.rows();
		int col = img.cols();
		if (y < 0) {
			y = 0;
		}
		if (y >= row) {
			y = row - 1;
		}
		if (x < 0) {
			x = 0;
		}
		if (x >= col) {
			x = col - 1;
		}
		if (width + x > col || width < 0) {
			width = col - x;
		}
		if (height + y > row || height < 0) {
			height = row - y;
		}

		if (width == 0 || height == 0) {
			return null;
		}

		return this;
	}

	@Override
	public String toString() {
		return Json.toJson(this);
	}

	public Area expandAny(int pex) {
		setX((int) (getX() - pex < 0 ? 0 : getX() - pex));
		setY((int) (getY() - pex < 0 ? 0 : getY() - pex));
		setWidth((int) (getWidth() + 2 * pex));
		setHeight((int) (getHeight() + 2 * pex));
		return this;
	}

	public Area expand(double times) {
		setX((int) (getX() * times));
		setY((int) (getY() * times));
		setWidth((int) (getWidth() * times));
		setHeight((int) (getHeight() * times));
		return this;
	}

	public Area expandWidth(double times) {
		setX((int) (getX() * times));
		setWidth((int) (getWidth() * times));
		return this;
	}

	public Area expandHeight(double times) {
		setY((int) (getY() * times));
		setHeight((int) (getHeight() * times));
		return this;
	}

	public Area toAreaByRect(Rect rect) {
		return new Area(rect.x, rect.y, rect.width, rect.height);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + height;
		result = prime * result + width;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Area other = (Area) obj;
		if (height != other.height)
			return false;
		if (width != other.width)
			return false;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}

	public String toMsg() {
		return Base64.encodeToString(XmlTool.toXml(this).replaceAll("\\s*", "").getBytes(), false);
	}

	public String toXml() {
		return XmlTool.toXml(this);
	}

	public int getArea() {
		return width * height;
	}

}
